#
# Copyright 2009 Red Hat, Inc. and/or its affiliates.
#
# Licensed to you under the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.  See the files README and
# LICENSE_GPL_v2 which accompany this distribution.
#


"""
NFS helper module
"""
import os

import constants
import misc
import storage_exception as se
from config import config
import errno

from remoteFileHandler import remoteFileHandlerPool
ros = remoteFileHandlerPool

# We must insure there are no white spaces in the NFS options
NFS_OPTIONS = "".join(config.get('irs', 'nfs_mount_options').split())

def mount(resource, mountPoint):
    """
    Mount the requested NFS resource
    """
    rc = 0
    if isMounted(resource, mountPoint):
        return rc

    if isStaleHandle(mountPoint):
        rc = umount(resource, mountPoint)
        if rc != 0:
            return rc

    cmd = [constants.EXT_MOUNT, "-o", NFS_OPTIONS, "-t", "nfs", resource, mountPoint]
    rc = misc.execCmd(cmd)[0]
    return rc

def umount(resource, mountPoint):
    """
    Unmount the requested resource from the associated mount point
    """
    rc = 0
    if (isMounted(resource, mountPoint)):
        cmd = [constants.EXT_UMOUNT, "-t", "nfs", "-f", mountPoint]
        rc = misc.execCmd(cmd)[0]
    return rc

def isStaleHandle(path):
    exists = ros.exists(path)
    stat = False
    try:
        ros.statvfs(path)
        stat = True
        ros.listdir(path)
    except OSError, ex:
        if ex.errno in (errno.EIO, errno.ESTALE):
            return  True
        # We could get contradictory results because of
        # soft mounts
        if (exists or stat) and ex.errno == errno.ENOENT:
            return True

    return False

def isMounted(resource, mountPoint):
    """Verify that NFS "resource" (if given) is mounted on "mountPoint"
    """
    mounts = misc.getMounts()
    for m in mounts:
        (res, mp, fs) = m[0:3]
        if (fs.startswith("nfs") and (mp == mountPoint)
         and ((not resource) or (res == resource))
         and (not isStaleHandle(mountPoint))):
            return True

    return False

def transformPath(remotePath):
    """
    Transform remote path to new one for local mount
    """
    return remotePath.replace('_','__').replace('/','_')

def validateAccess(path):
    """
    Validate the RWX access to a given path
    """
    if not ros.access(path, os.R_OK | os.W_OK | os.X_OK):
        raise se.StorageServerAccessPermissionError()
